package com.luom.fsp.service.impl;

import java.util.*;

import java.math.BigDecimal;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luom.fsp.common.ErrorCode;
import com.luom.fsp.constant.CommonConstant;
import com.luom.fsp.constant.RedisConstant;
import com.luom.fsp.exception.ThrowUtils;
import com.luom.fsp.mapper.ProductSKUMapper;
import com.luom.fsp.model.dto.productSKU.ProductSKUQueryRequest;
import com.luom.fsp.model.entity.ProductSKU;
import com.luom.fsp.model.entity.User;
import com.luom.fsp.model.enums.ProductStatusEnum;
import com.luom.fsp.model.vo.ProductSKUVO;
import com.luom.fsp.model.vo.UserVO;
import com.luom.fsp.service.ProductSKUService;
import com.luom.fsp.service.UserService;
import com.luom.fsp.utils.SqlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;

/**
 * 商品规格服务实现
 */
@Service
@Slf4j
public class ProductSKUServiceImpl extends ServiceImpl<ProductSKUMapper, ProductSKU> implements ProductSKUService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 校验数据
     *
     * @param productSKU
     * @param add        对创建的数据进行校验
     */
    @Override
    public void validProductSKU(ProductSKU productSKU, boolean add) {
        ThrowUtils.throwIf(productSKU == null, ErrorCode.PARAMS_ERROR);

        Long productId = productSKU.getProductId();
        String description = productSKU.getDescription();
        BigDecimal price = productSKU.getPrice();
        Integer stock = productSKU.getStock();
        String quantity = productSKU.getQuantity();
        String status = productSKU.getStatus();
        // 创建数据时，参数不能为空
        if (add) {
            ThrowUtils.throwIf(ObjectUtils.isEmpty(productId), ErrorCode.PARAMS_ERROR, "商品ID不能为空");
            ThrowUtils.throwIf(ObjectUtils.isEmpty(price), ErrorCode.PARAMS_ERROR, "价格不能为空");
            ThrowUtils.throwIf(ObjectUtils.isEmpty(stock), ErrorCode.PARAMS_ERROR, "库存不能为空");
            ThrowUtils.throwIf(ObjectUtils.isEmpty(quantity), ErrorCode.PARAMS_ERROR, "规格数量不能为空");
        }
        // 修改数据时，有参数则校验
        if (StringUtils.isNotBlank(description)) {
            ThrowUtils.throwIf(description.length() > 512, ErrorCode.PARAMS_ERROR, "描述过长");
        }
        if (ObjectUtils.isNotEmpty(price)) {
            ThrowUtils.throwIf(price.compareTo(BigDecimal.ZERO) < 0, ErrorCode.PARAMS_ERROR, "价格不能为负数");
        }
        if (ObjectUtils.isNotEmpty(stock)) {
            ThrowUtils.throwIf(stock < 0, ErrorCode.PARAMS_ERROR, "库存不能为负数");
        }
        if (ObjectUtils.isNotEmpty(quantity)) {
            ThrowUtils.throwIf(quantity.length() > 20, ErrorCode.PARAMS_ERROR, "规格数量过长");
        }
        if (StringUtils.isNotBlank(status)) {
            ThrowUtils.throwIf(!ProductStatusEnum.getValues().contains(status), ErrorCode.PARAMS_ERROR, "状态错误");
        }
    }

    /**
     * 获取查询条件
     *
     * @param productSKUQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<ProductSKU> getQueryWrapper(ProductSKUQueryRequest productSKUQueryRequest) {
        QueryWrapper<ProductSKU> queryWrapper = new QueryWrapper<>();
        if (productSKUQueryRequest == null) {
            return queryWrapper;
        }

        Long id = productSKUQueryRequest.getId();
        Long productId = productSKUQueryRequest.getProductId();
        String description = productSKUQueryRequest.getDescription();
        BigDecimal price = productSKUQueryRequest.getPrice();
        Integer stock = productSKUQueryRequest.getStock();
        String quantity = productSKUQueryRequest.getQuantity();
        String status = productSKUQueryRequest.getStatus();
        String sortField = productSKUQueryRequest.getSortField();
        String sortOrder = productSKUQueryRequest.getSortOrder();

        // 模糊查询
        queryWrapper.like(StringUtils.isNotBlank(description), "description", description);
        queryWrapper.like(StringUtils.isNotBlank(quantity), "quantity", quantity);

        // 精确查询
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjectUtils.isNotEmpty(productId), "productId", productId);
        queryWrapper.gt(ObjectUtils.isNotEmpty(price), "price", price);
        queryWrapper.gt(ObjectUtils.isNotEmpty(stock), "stock", stock);
        queryWrapper.eq(ObjectUtils.isNotEmpty(status), "status", status);
        // 排序规则
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    /**
     * 获取商品规格封装
     *
     * @param productSKU
     * @param request
     * @return
     */
    @Override
    public ProductSKUVO getProductSKUVO(ProductSKU productSKU, HttpServletRequest request) {
        // 对象转封装类
        ProductSKUVO productSKUVO = ProductSKUVO.objToVo(productSKU);
        if (productSKU == null) {
            return null;
        }
        String sales = (String) stringRedisTemplate.opsForHash()
                .get(RedisConstant.SKU_SALES_STATISTIC_KEY + productSKU.getProductId(), productSKU.getId().toString());
        if (sales != null) {
            productSKUVO.setSales(Integer.parseInt(sales));
        }
        return productSKUVO;
    }

    /**
     * 分页获取商品规格封装
     *
     * @param productSKUPage
     * @param request
     * @return
     */
    @Override
    public Page<ProductSKUVO> getProductSKUVOPage(Page<ProductSKU> productSKUPage, HttpServletRequest request) {
        List<ProductSKU> productSKUList = productSKUPage.getRecords();
        Page<ProductSKUVO> productSKUVOPage = new Page<>(productSKUPage.getCurrent(), productSKUPage.getSize(), productSKUPage.getTotal());
        if (CollUtil.isEmpty(productSKUList)) {
            return productSKUVOPage;
        }
        // 对象列表 => 封装对象列表
        List<ProductSKUVO> productSKUVOList = productSKUList.stream().map(ProductSKUVO::objToVo).collect(Collectors.toList());

        // 获取销量
        Map<Long, Integer> sales = getBatchSalesFromRedis(productSKUList);

        // 填充销量
        productSKUVOList.forEach(productSKUVO -> {
            Integer skuSales = sales.get(productSKUVO.getId());
            productSKUVO.setSales(skuSales);
        });

        productSKUVOPage.setRecords(productSKUVOList);
        return productSKUVOPage;
    }

    // 批量查询销量
    private Map<Long, Integer> getBatchSalesFromRedis(List<ProductSKU> skuList) {
        // 保存查询顺序
        List<Pair<Long, Long>> querySequence = new ArrayList<>(skuList.size());

        // 构建Pipeline查询
        List<Object> results = stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (ProductSKU sku : skuList) {
                String hashKey = RedisConstant.SKU_SALES_STATISTIC_KEY + sku.getProductId();
                String field = sku.getId().toString();

                // 记录查询顺序
                querySequence.add(Pair.of(sku.getId(), sku.getProductId()));

                byte[] rawKey = stringRedisTemplate.getStringSerializer().serialize(hashKey);
                byte[] rawField = stringRedisTemplate.getStringSerializer().serialize(field);
                if (rawKey != null && rawField != null) {
                    connection.hGet(rawKey, rawField);
                }
            }
            return null;
        });

        // 构建结果映射
        Map<Long, Integer> salesMap = new HashMap<>(skuList.size());
        for (int i = 0; i < results.size(); i++) {
            Pair<Long, Long> skuInfo = querySequence.get(i);
            Long skuId = skuInfo.getKey();
            String value = (String) results.get(i);

            salesMap.put(skuId, value != null ? Integer.parseInt(value) : 0);
        }

        return salesMap;
    }

}
